package engine.systems.timeline.timeline
{
	import ash.core.Component;
	
	import engine.utils.DataUtils;
	
	import flash.display.MovieClip;
	
	public class Timeline extends Component
	{
		public static const PLAY:String 			= "play";
		public static const STOP:String 			= "stop";
		public static const GOTO_AND:String			= "gotoAnd";
		public static const GOTO_AND_PLAY:String 	= "gotoAndPlay";
		public static const GOTO_AND_STOP:String	= "gotoAndStop";
		
		public static const LABEL_FIRST_FRAME:String 	= "first";
		public static const LABEL_LAST_FRAME:String 	= "last";
		
		internal var _frame:int = 1;
		internal var _playing:Boolean;
		internal var _time:Number = 0;
		
		internal var _manualFrameEvent:FrameEvent;
		internal var _data:Vector.<FrameData> = new Vector.<FrameData>();
		internal var _labelHandlers:Vector.<LabelHandler> = new Vector.<LabelHandler>();
		
		public var locked:Boolean = false;
		public var forward:Boolean;
		public var frameRate:Number;
		
		public function Timeline(playing:Boolean = false, frameRate:Number = 0.03333, forward:Boolean = true)
		{
			this._playing 	= playing;
			this.frameRate 	= frameRate;
			this.forward 	= forward;
		}
		
		override public function destroy():void
		{
			this._data = null;
		}
		
		public final function getFrameDataByFrame(frame:int):FrameData
		{
			return this._data[frame - 1];
		}
		
		public final function getFrameDataByLabel(label:String):FrameData
		{
			for each(var data:FrameData in this._data)
			{
				if(data.label == label) return data;
			}
			
			return null;
		}
		
		public final function get data():Vector.<FrameData> { return this._data; }
		public final function get frame():int 				{ return this._frame; }
		public final function get playing():Boolean 		{ return this._playing; }
		
		public final function play():void 				{ this._manualFrameEvent = new FrameEvent(Timeline.PLAY); }
		public final function stop():void 				{ this._manualFrameEvent = new FrameEvent(Timeline.STOP); }
		public final function gotoAndPlay(frame:*):void { this._manualFrameEvent = new FrameEvent(Timeline.GOTO_AND_PLAY, frame); }
		public final function gotoAndStop(frame:*):void { this._manualFrameEvent = new FrameEvent(Timeline.GOTO_AND_STOP, frame); }
		
		public final function parseClip(clip:MovieClip):void
		{
			var totalFrames:int	= clip.totalFrames;
			this._data.length 	= 0;
			
			for(var i:int = 1; i <= totalFrames; i++)
			{
				clip.gotoAndStop(i);
				
				var frameData:FrameData = new FrameData();
				this._data.push(frameData);
				
				var frameLabel:String = clip.currentFrameLabel;
				if(!frameLabel) continue;
				
				var labelParts:Array = frameLabel.split(",");
				switch(labelParts.length)
				{
					case 1:
						frameData.label = labelParts[0];
						break;
					
					case 2:
						frameData.label = labelParts[0];
						
						var action:String = labelParts[1];
						
						if(action == Timeline.PLAY || action == Timeline.PLAY + "()")
						{
							frameData.event = new FrameEvent(Timeline.PLAY);
						}
						else if(action == Timeline.STOP || action == Timeline.STOP + "()")
						{
							frameData.event = new FrameEvent(Timeline.STOP);
						}
						else if(action.indexOf(Timeline.GOTO_AND) > -1)
						{
							var open:int 	= action.indexOf("(") + 1;
							var close:int 	= action.indexOf(")");
							var frame:* 	= DataUtils.cast(action.slice(open, close));
							
							if(action.indexOf(Timeline.GOTO_AND_PLAY) > -1)
							{
								frameData.event = new FrameEvent(Timeline.GOTO_AND_PLAY, frame);
							}
							else if(action.indexOf(Timeline.GOTO_AND_STOP) > -1)
							{
								frameData.event = new FrameEvent(Timeline.GOTO_AND_STOP, frame);
							}
							else
							{
								throw new Error("Timeline :: parseClip() :: Clip <" + clip.name + "> has an invalid label!");
							}
						}
						else
						{
							throw new Error("Timeline :: parseClip() :: Clip <" + clip.name + "> has an invalid label!");
						}
						break;
					
					default:
						throw new Error("Timeline :: parseClip() :: Clip <" + clip.name + "> has an invalid label!");
						break;
				}
			}
			
			clip.gotoAndStop(1);
		}
	}
}